﻿#include "p2p_server.h"
#include <QFile>
#include <QFileDialog>
#include <QTime>

P2P_Server::P2P_Server(QObject *parent, int port)
    :QTcpServer(parent)
{
    tcp_client_socket = NULL;
    listen(QHostAddress::Any, port);
}

void P2P_Server::incomingConnection(qintptr socketDescriptor){//重写监听到tcp连接时的函数
    tcp_client_socket = new QTcpSocket(this);
    //QTcpServer连接后的信号函数绑定
    connect(tcp_client_socket,SIGNAL(readyRead()),this,SLOT(checkdata()));//作为p2p的服务器处理请求
    connect(tcp_client_socket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
    tcp_client_socket->setSocketDescriptor(socketDescriptor);
    qDebug() << "connected";
}

//#len#filepath#
#define PAK_ERR "PKE"//发送的包是错误的
#define FP_ERR  "FPE"//文件路径错误
#define SUCC    "SUC"//请求正确
void P2P_Server::checkdata(){

    if(tcp_client_socket->bytesAvailable() >= 11){
        //获取请求头信息
        char buf[1024];
        tcp_client_socket->read(buf,11);
        QString msg;

        if(buf[0] != '#'){//请求的第一个字节错误，说明发送的包是错的
            msg = PAK_ERR;
            tcp_client_socket->write(msg.toLatin1(), msg.length());
            return;
        }

        msg = buf;
        long len = msg.mid(1, 10).toLong();//获取文件路径名的长度
        tcp_client_socket->read(buf,len + 3);//读取文件的路径名

        msg = buf;
        qDebug()<<msg<<endl;
        QString breakpoint=msg.mid(len + 2, 1);//获取文件断点的位置

        QString filepath = msg.mid(1, len);//获取路径名
        qDebug()<<filepath<<endl;
        qDebug()<<"breakpoint"+breakpoint<<endl;

        if(breakpoint == "-"){//"-1"取字符串只取到了-号
            breakpoint = "-1";
        }

        transfer(filepath,breakpoint);//breakpoint=-1则没有异常中断。大于0需要断点续传。0表示0-256字节块，1表示256-512字节块
    }

}

//将文件分块传输，一次传输256字节
void P2P_Server::transfer(QString& filepath,QString& breakpoint){//往套接字里面传输p2p客户端需要的文件
    QFile file(filepath);
    QFileInfo info(file);
    qint64 filesize = info.size();
    QString msg;

    if(breakpoint == "-1"){//不是断点续传
     if(file.open(QIODevice::ReadOnly)){//文件打开成功就开始传输
        char buf[257];
        msg = SUCC;
        tcp_client_socket->write(msg.toLatin1(), msg.length());//先向客户端发送请求成功的响应，接下来开始发送文件

        for(int i = 0; i < filesize / 256; ++i) {//将文件分块传输，一次传输256字节
            file.read(buf, 256);
            qDebug() << tcp_client_socket->write(buf, 256);//往客户端传输256字节的文件块
            qDebug() << tcp_client_socket->waitForBytesWritten(30000);//等待上一个文件块传输完成，超时时间是3秒
        }
        file.read(buf, filesize % 256);//将剩余不够组成一块的数据也发送过去
        qDebug() << tcp_client_socket->write(buf, filesize % 256);
        qDebug() <<  tcp_client_socket->waitForBytesWritten(30000);
    }
    else{//文件打开失败，向客户端发送错误信息
        msg = FP_ERR;
        tcp_client_socket->write(msg.toLatin1(), msg.length());
    }
   }else{//断点续传
        bool flag=false;//用于进入断点文件的位置
        if(file.open(QIODevice::ReadOnly)){//文件打开成功就开始传输
           char buf[257];
           msg = SUCC;
           tcp_client_socket->write(msg.toLatin1(), msg.length());//先向客户端发送请求成功的响应，接下来开始发送文件

           for(int i = 0; i < filesize / 256; ++i) {//将文件分块传输，一次传输256字节
               file.read(buf, 256);
               if(breakpoint == QString::number(i)){
                   flag=true;
               }
               if(flag){//读取到断点的位置才开始往请求方发送字节流文件
               qDebug() << tcp_client_socket->write(buf, 256);//往客户端传输256字节的文件块
               qDebug() << tcp_client_socket->waitForBytesWritten(9000);//等待上一个文件块传输完成，超时时间是3秒

               QTime _Timer = QTime::currentTime().addMSecs(500);//1s
                   while( QTime::currentTime() < _Timer );
               }
           }
           file.read(buf, filesize % 256);//将剩余不够组成一块的数据也发送过去
           qDebug() << tcp_client_socket->write(buf, filesize % 256);
           qDebug() <<  tcp_client_socket->waitForBytesWritten(9000);
       }
       else{//文件打开失败，向客户端发送错误信息
           msg = FP_ERR;
           tcp_client_socket->write(msg.toLatin1(), msg.length());
       }
     }
}

void P2P_Server::slotDisconnected(){

}

P2P_Server::~P2P_Server(){
    if(tcp_client_socket != NULL)
        delete tcp_client_socket;
}

